package com.tnsw.facebookautoliker.helper.command;

import java.net.HttpURLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Hashtable;

import org.json.JSONArray;
import org.json.JSONObject;

import android.content.Context;
import android.os.Bundle;

import com.facebook.HttpMethod;
import com.facebook.LoggingBehavior;
import com.facebook.Request;
import com.facebook.RequestBatch;
import com.facebook.Response;
import com.facebook.Session;
import com.facebook.Settings;
import com.tnsw.coreutils.MyLog;
import com.tnsw.coreutils.StaticConfig;
import com.tnsw.facebookautoliker.database.DBManager;
import com.tnsw.facebookautoliker.helper.FacebookBGManager;
import com.tnsw.facebookautoliker.helper.FacebookCommandObject;
import com.tnsw.facebookautoliker.helper.GeneralManager;

public class FQLBase extends FacebookCommandObject implements Request.Callback {
	
	private String fql;
	
	protected FacebookBGManager fbm;
	protected DBManager dbm;
	protected GeneralManager gm;
	
	private int limit = 25;  		// this is limit per query
	private int maxRecord = 50;		// this is total record count
	private String pagingPointColumn = "created_time";	// Using this column as paging point
	private String pagingCondition = "";
	private int currentReturnCount = 0;
	private ArrayList<JSONObject> arrJSONObjects;
	
	private FQLInterface fqli;
	private String orderCondition = "";
	
	public FQLBase(Context context, String fql, FacebookCommandObject parent) {
		super(context, parent);
		this.tag = "FQLBase";
		this.context = context;
		this.fql = fql;
		
		this.fbm = FacebookBGManager.getInstance(context);
		this.dbm = DBManager.getInstance(context);
		this.gm = GeneralManager.getInstance();
	}
	
	public FQLBase(Context context, FacebookCommandObject parent) {
		super(context, parent);
		this.context = context;
		
		this.fbm = FacebookBGManager.getInstance(context);
		this.dbm = DBManager.getInstance(context);
		this.gm = GeneralManager.getInstance();
	}
		
	public void setFQL(String fql) {
		this.fql = fql;
	}
	
	public String getFQL() {
		return(this.fql);
	}
	
	public void setOrderCondition(String s) {
		this.orderCondition = s;
	}
	
	public String getOrderCondition() {
		return(this.orderCondition);
	}
	
	public void setFQLInterface(FQLInterface fqli) {
		this.fqli = fqli;
	}
	
	public void setMaxRecord(int max) {
		this.maxRecord = max;
	}
	
	public int getMaxRecord() {
		return(this.maxRecord);
	}
	
	public void setLimit(int i) {
		this.limit = i;
	}
	
	public int getLimit() {
		return(this.limit);
	}
	
	public String getPagingColumn() {
		return(this.pagingPointColumn);
	}
	/**
	 * 
	 * 
	 * @param column - the column for doing paging, set this to null to disable paging
	 */
	public void setPagingColumn(String column) {
		this.pagingPointColumn = column;
	}
	
	public int getCurrentReturnCount() {
		return(this.currentReturnCount);
	}
	
	@Override
	public void onCompleted(Response response) {
		this.handleResult(response);
	}
		
	private void executeInternal() {
		
		if (MyLog.isProduction == false) {
			Settings.addLoggingBehavior(LoggingBehavior.REQUESTS);
		}
		
		Session session = Session.openActiveSessionFromCache(this.context);
		if (session != null) {
			MyLog.d(tag, "access_token=" + session.getAccessToken());
			
			Bundle params = null;
			params = new Bundle();
			String finalFQL = this.fql;
			if (this.pagingCondition.equals("") == false) {
				if (this.fql.toLowerCase().contains("where") == false) {
					finalFQL = finalFQL + " where " + this.pagingCondition;
				} else {
					finalFQL = finalFQL + " and " + this.pagingCondition;
				}	
			}
			
			if (this.orderCondition.equals("") == false) {
				finalFQL = finalFQL + " " + this.orderCondition + " ";
			}
			
			finalFQL = finalFQL + " LIMIT " + String.valueOf(this.limit);
			params.putString("q", finalFQL);
			
			MyLog.d(tag, "finalFQL=" + finalFQL);
			
			Request req = new Request(session, "/fql", params, HttpMethod.GET);
			req.setCallback(this);
			
			this.standardExecute(req);		
			
		} else {
			this.fbm.updateCommandStatus(this, 500, null);
		}
		
	}

	@Override
	public void execute() {
		super.execute();
		this.currentReturnCount = 0;
		this.pagingCondition = "";
		this.arrJSONObjects = new ArrayList<JSONObject>();
		this.executeInternal();
	}
	
	@Override
	protected void handleResult(Response response) {
		MyLog.d(tag, "handleResult()");
		
		super.handleResult(response);
		
		if (response.getGraphObject() != null) {
			//MyLog.d(tag, response.getGraphObject().toString());
			JSONArray jData = (JSONArray) response.getGraphObject().getProperty("data");
			int i;
			boolean alreadyEnd = false;
			for (i = 0; i < jData.length(); i++) {
				try {
					this.currentReturnCount += 1;
					JSONObject jo = (JSONObject) jData.get(i);
					if (StaticConfig.DEBUGMODE) {
						MyLog.d(tag, this.currentReturnCount + "=" + jo.toString());	
					}
																	
					if (this.fqli != null) {
						boolean b = this.fqli.onSingleRecordFetched(this, this.currentReturnCount, jo);
						
						if (b == true) {
							// Need to exit query now
							MyLog.d(tag, "END NOW (onSingleRecordFetched=true)");
							this.fbm.updateCommandStatus(this, 200, null);
							if (this.fqli != null) {
								this.fqli.onEndQuery(this, this.arrJSONObjects);
									
							}
							alreadyEnd = true;
							break;
							
						}
					}
					
					this.arrJSONObjects.add(jo);
												
					if ( ( this.pagingPointColumn != null) && (this.pagingPointColumn.equals("") == false) ) {
						if (i == jData.length()-1) {
							String pagingPointValue = jo.getString(this.pagingPointColumn);
							if (this.orderCondition != null) {
								if (this.orderCondition.toLowerCase().contains("desc")) {
									this.pagingCondition = this.pagingPointColumn + "<'" + pagingPointValue + "'";		
								} else {
									this.pagingCondition = this.pagingPointColumn + ">'" + pagingPointValue + "'";
								}
							}
							
						}	
					}
					
						
					if (this.currentReturnCount == this.maxRecord) {
						MyLog.d(tag, "END NOW");
						this.fbm.updateCommandStatus(this, 200, null);
						if (this.fqli != null) {
							this.fqli.onEndQuery(this, this.arrJSONObjects);
								
						}
						alreadyEnd = true;
						break;
					}
					
				} catch (Exception e) {
					MyLog.e(tag, "handleRequest(inside, sql=" + response.getRequest().getParameters().getString("q") + ") - " + e.toString(), e);
					
				}
			}
				
			if (jData.length() > 0) {  // Still have some record to go further
				if ( (this.currentReturnCount < this.maxRecord) && (this.pagingPointColumn != null) && (alreadyEnd == false) ) {
					// Still not end, currentReturnCount not reach and pagingPointColumn is defined
					this.executeInternal();
				} else {
					if (alreadyEnd == false) {
						// Need to exit query now because no paging is allowed
						MyLog.d(tag, "END NOW (pagingPointColumn == null)");
						this.fbm.updateCommandStatus(this, 200, null);
						if (this.fqli != null) {
							this.fqli.onEndQuery(this, this.arrJSONObjects);
								
						}
						alreadyEnd = true;	
					}
					
				}
				
			} else {
				MyLog.d(tag, "Found no further record, better end now");
				if (alreadyEnd == false) {
					this.fbm.updateCommandStatus(this, 200, null);
					if (this.fqli != null) {
						this.fqli.onEndQuery(this, this.arrJSONObjects);
					}
				}
					
			}
				
		} else {
			if (this.fqli != null) {
				this.fqli.onEndQuery(this, this.arrJSONObjects);
			}
		}
			

	}

}
